拓扑排序 dfs

拓扑排序简单来说就是把一个图的所有节点排序,使得每一条有向边(u,v)对应的u都排在v的前面。 

拓扑排序最大的用途就是判断一个有向图是否有环,当然判断还有一种方法就是Floyd算法。

如果用邻接表的话拓扑排序的时间复杂度是O(N*E),邻接矩阵是O(N^2),N表示顶点数,E表示边数,Floyd时间复杂度是O(N^3)。

性质
1、 拓扑排序在有向无环图中才能排出有效的序列,否则能判断该有向图有环。
2、如果输入的有向图中的点,不存在入度为0的点,则该有向图存在回路
3、如果存在的入度为0的点大于一个,则该有向图肯定不存在一个可以确定的拓扑序列但并不妨碍拓扑排序 

下面给出核心程序:

  1. vector<int>g[N];//邻接表存储  
  2. int vis[N],topo[N],cnt;  
  3.   
  4. bool dfs(int u)  
  5. {  
  6.     vis[u] = -1;//-1用来表示顶点u正在访问  
  7.     for(int i = 0 ; i < g[u].size() ; i ++)  
  8.     {  
  9.         if(vis[g[u][i]] == -1)//表示这个点进入了两次,肯定出现了环  
  10.             return false;  
  11.         else if(vis[g[u][i]] == 0)  
  12.         {  
  13.             dfs(g[u][i]);  
  14.         }  
  15.     }  
  16.     vis[u] = 1;  
  17.     topo[cnt++] = u;//放到结果数组里,输出的时候记得倒序输出,(回溯的原因)  
  18.     return true;  
  19. }  
  20.   
  21. bool toposort(int n)  
  22. {  
  23.     memset(vis,0,sizeof(vis));  
  24.     for(int i = 1 ; i <= n ; i ++)  
  25.     {  
  26.         if(!vis[i])  
  27.         {  
  28.             if(!dfs(i)) return false;//huan  
  29.         }  
  30.     }  
  31.     return true;  
  32. }  


非递归代码,这段代码无法判断是否有环

  1. for(i=1;i<=n;i++)//外层循环n次,in[]数组用来记录每个点的入度  
  2.     {  
  3.         j=1;  
  4.         while(in[j]!=0) j++;//从第一个节点开始找到一个节点入度为0的节点  
  5.         ans[i]=j;//存储答案  
  6.         in[j]=-1;//将该节点的入度更新为-1  
  7.         for( k=1;k<=n;k++)//将所有与节点j相连的节点的入度值全部减1  
  8.             if(vis[j][k]==1) in[k]--;  
  9.     }  


晚上做题的时候想起来,拓扑排序还有一个重要的功能就是判断节点是一条链,还是在某个节点出现了分叉,这个很好理解,就用上面的非递归代码就可以判断,每次找入度为0的节点数目只能有1个,如果出现了两个则说明在该节点的父亲节点出现了分叉。

转:http://blog.csdn.net/acceptedxukai/article/details/6959882

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
拓扑排序是一种对有向无环图进行排序的算法,它可以用来确定前驱关系,验证图中是否有环等。拓扑排序的基本思想是将图中的节点按照一定的顺序排列,使得所有的有向边从排在前面的节点指向排在后面的节点。在实际应用中,拓扑排序常常被用来解决任务调度、编译顺序等问题。 在C++中,可以使用DFS算法进行拓扑排序。具体实现方法是,对于每个节点,先将其标记为正在访问中,然后遍历其所有的邻居节点,如果邻居节点已经被访问过了,就说明存在环,返回false;如果邻居节点还没有被访问过,就递归地对其进行访问。当所有的邻居节点都被访问完毕后,将该节点标记为已经访问过,并将其加入到拓扑序列中。最后,将拓扑序列倒序输出即可。 下面是一个使用DFS算法进行拓扑排序的C++代码示例: ``` const int maxn = 100; int c[maxn]; int topo[maxn], t, n; int G[maxn][maxn]; bool dfs(int u) { c[u] = -1; for(int v = 0; v < n; v++) { if(G[u][v]) { if(c[v] < 0) return false; else if(!c[v] && !dfs(v)) return false; } } c[u] = 1; topo[--t] = u; return true; } bool topoSort() { t = n; memset(c,0,sizeof(c)); for(int u = 0; u < n; u++){ if(!c[u] && !dfs(u)) return false; } return true; } int main() { char ch[100] = {'a', 'b', 'c', 'd'}; n = 4; G[0][1] = 1; G[2][1] = 1; G[3][2] = 1; if(!topoSort()){ printf("无法拓扑排序\n"); return 0; } for(int i = 0; i < 4; i++){ printf("%c ", ch[topo[i]]); } printf("\n"); } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值